/**
 * 
 */
package edu.arizona.bio5.onto.decomposition.persistent.file;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.OWLDataFactory;

import uk.ac.manchester.cs.graph.DirectedGraph;
import uk.ac.manchester.cs.graph.io.DOTReaderImpl;
import uk.ac.manchester.cs.graph.io.GraphReader;
import uk.ac.manchester.cs.owlapi.modularity.ModuleType;
import edu.arizona.bio5.onto.decomposition.Atom;
import edu.arizona.bio5.onto.decomposition.persistent.ADLoader;
import edu.arizona.bio5.onto.decomposition.persistent.ADPersistenceException;
import edu.arizona.bio5.onto.decomposition.persistent.AtomLoader;
import edu.arizona.bio5.onto.decomposition.persistent.LabelLoader;
import edu.arizona.bio5.onto.decomposition.persistent.PersistentAtomReader;
import edu.arizona.bio5.onto.decomposition.persistent.PersistentAtomicDecomposition;
import edu.arizona.bio5.onto.decomposition.persistent.PersistentAtomicDecompositionImpl;

/**
 * @author Pavel Klinov
 *
 */
public class DiskADLoader implements ADLoader {

	private final File mRootDir;
	
	public DiskADLoader(final File adDir) {
		mRootDir = adDir;
	}
	/* 
	 * 
	 */
	@Override
	public PersistentAtomicDecomposition load() throws ADPersistenceException {

		if (!mRootDir.exists() || !mRootDir.isDirectory()) {
			
			throw new ADPersistenceException("Invalid AD directory, loading failed");
		}
 
		OWLDataFactory factory = OWLManager.getOWLDataFactory();
		Map<Object, Atom> idAtomMap = new HashMap<Object, Atom>();
		ModuleType type = loadModuleType(mRootDir);
		DirectedGraph<Atom, Object> adGraph = loadGraph(mRootDir, idAtomMap, new DiskAtomLoader(mRootDir));
		Map<URI, Set<Atom>> termIndex = loadTermBasedIndex(mRootDir, idAtomMap);

		loadAtomLabels(mRootDir, idAtomMap, new SeedSigsLabelLoader(factory));
		
		return new PersistentAtomicDecompositionImpl(null, adGraph, termIndex, type);
	}
	
	private void loadAtomLabels(File dir, Map<Object, Atom> idAtomMap, LabelLoader<String> labelLoader)  throws ADPersistenceException {

		File labelsFile = new File(dir.getAbsolutePath() + "/" + DiskADConstants.LABELS_FILE);
		
		try {
			
			System.out.print("Loading labels... ");
			
			BufferedReader reader = new BufferedReader(new FileReader(labelsFile));
			String line = null;
			
			while ((line = reader.readLine()) != null) {
				
				String[] parts = line.split("->");
				Atom atom = idAtomMap.get(parts[0]);
				//The second part is a list of labels
				labelLoader.setInput(parts[1]);
				
				atom.setLabel(labelLoader.load());
			}
			
			System.out.println("done!");
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			throw new ADPersistenceException("Labels file not found");
			
		} catch (IOException e) {
			e.printStackTrace();
			throw new ADPersistenceException("A problem with the labels file: " + e.getMessage());
		}
	}

	private Map<URI, Set<Atom>> loadTermBasedIndex(File dir, Map<Object, Atom> idAtomMap)  throws ADPersistenceException {

		File termIndexFile = new File(dir.getAbsolutePath() + "/" + DiskADConstants.TERM_INDEX_FILE);
		Map<URI, Set<Atom>> termIndex = new HashMap<URI, Set<Atom>>();
		
		try {
			
			System.out.print("Loading term-based index... ");
			
			BufferedReader reader = new BufferedReader(new FileReader(termIndexFile));
			String line = null;
			
			while ((line = reader.readLine()) != null) {
				
				String[] parts = line.split("->");
				URI term = URI.create(parts[0]);
				//The second part should be a list of atom IDs
				String[] ids = parts[1].split(",");
				Set<Atom> atoms = new HashSet<Atom>(ids.length);
				
				for (String id : ids) {
					
					atoms.add(idAtomMap.get(id));
				}
				
				termIndex.put(term, atoms);
			}
			
			System.out.println("done!");
			
			return termIndex;
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			throw new ADPersistenceException("Term index file not found");
			
		} catch (IOException e) {
			e.printStackTrace();
			throw new ADPersistenceException("A problem with the term index file: " + e.getMessage());
		}
	}


	private DirectedGraph<Atom, Object> loadGraph(File dir, Map<Object, Atom> idAtomMap, AtomLoader atomLoader)  throws ADPersistenceException {

		File graphFile = new File(dir.getAbsolutePath() + "/" + DiskADConstants.GRAPH_FILE);
		GraphReader<Atom, Object> graphReader = new DOTReaderImpl<Atom, Object>();
		
		graphReader.setNodeReader(new PersistentAtomReader(atomLoader));
		
		try {
			
			System.out.print("Loading graph... ");
			
			DirectedGraph<Atom, Object> adGraph = (DirectedGraph<Atom, Object>)graphReader.read(new FileReader(graphFile));
			
			for (Atom atom : adGraph.getVertices()) idAtomMap.put(atom.getID(), atom);
			
			System.out.println("done!");
			
			return adGraph;
			
		} catch (FileNotFoundException e) {

			throw new ADPersistenceException("AD graph file not found");
			
		} catch (IOException e) {

			throw new ADPersistenceException("AD graph could not be loaded");
		}
	}


	private ModuleType loadModuleType(File dir) throws ADPersistenceException {

		File mdFile = new File(dir.getAbsolutePath() + "/" + DiskADConstants.MODULE_TYPE_FILE);
		
		try {
			
			BufferedReader reader = new BufferedReader(new FileReader(mdFile));
			String modTypeString = reader.readLine();
			
			return ModuleType.valueOf(modTypeString);
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			throw new ADPersistenceException("Module type's file not found");
			
		} catch (IOException e) {
			e.printStackTrace();
			throw new ADPersistenceException("A problem with the module type's file: " + e.getMessage());
		}
	}	
}